#include "thread_pool_impl.h"

#include <iostream>
#include <unistd.h>

sptr<ThreadPoolImpl> ThreadPoolImpl::GetInstance()
{
    if (instance == nullptr) {
        static std::mutex mutex;
        std::lock_guard<std::mutex> lock(mutex);
        if (instance == nullptr) {
            instance = new ThreadPoolImpl();
        }
    }
    return instance;
}

void ThreadPoolImpl::PostTask(ThreadPoolTask task, std::string name)
{
    {
        std::lock_guard<std::mutex> lock(tasksMutex);
        tasks.push({.task = task, .name = name});
    }
    sem_post(&taskSem); // ++
}

ThreadPoolImpl::ThreadPoolImpl()
{
    sem_init(&taskSem, false, 0); // = 0

    int cpuNumber = 1;
    for (int i = 0; i < cpuNumber; i++) {
        auto func = std::bind(&ThreadPoolImpl::WorkThreadMain, this, i);
        workThreads.push_back(std::make_unique<std::thread>(func));
    }
}

ThreadPoolImpl::~ThreadPoolImpl()
{
    running = false;
    for (int i = 0; i < workThreads.size(); i++) {
        sem_post(&taskSem); // ++
    }
    for (const auto &workThread : workThreads) {
        workThread->join();
    }

    sem_destroy(&taskSem); // ~
}

void ThreadPoolImpl::WorkThreadMain(int id)
{
    // std::cout << "WorkThread: " << id << "started" << std::endl;

    while (true) {
        sem_wait(&taskSem); // --
        if (running == false) {
            break;
        }

        Task task;
        {
            std::lock_guard<std::mutex> lock(tasksMutex);
            task = tasks.front();
            tasks.pop();
        }

        // std::cout << "Work(" << id << "): " << task.name << " started" << std::endl;
        task.task();
        // std::cout << "Work(" << id << "): " << task.name << " end" << std::endl;
    }

    // std::cout << "WorkThread: " << id << "stoped" << std::endl;
}
